package com.xqkj.commons.virtualdb.templates.impl;

import com.xqkj.commons.model.HandleResult;
import com.xqkj.commons.model.basicdo.BasicDo;
import com.xqkj.commons.virtualdb.model.*;
import com.xqkj.commons.virtualdb.service.functions.*;
import com.xqkj.commons.virtualdb.templates.AddAttributeToVirtualDb;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @author lwt<br>
 * @description <br>
 * @date 2020/1/16
 */
public class DefAddAttributeToVirtualDb implements AddAttributeToVirtualDb {

    private Function<ModelBasicAttributeSvModel,HandleResult<ModelAttributePkAndShadingInfoModel>> attributeInsertFunction;
    //
    private Function<UnionIdxMappingSvModel,Integer> insertUidxMappingFunction;
    private Function<GetByUnionIdxParameterModel,BasicDo> getByAttributeUidxFunction;
    private Function<String,Boolean> lockFunction;
    private Consumer<String> unLockFunction;
    //
    private Function<ParametersWrappedModel<BasicDo>,VirtualDbLockInfoModel> lockInfoGetter;
    private Function<VirtualDbLockInfoModel,HandleResult<String>> unionTmpMappingWriter;
    private Function<VirtualDbLockInfoModel, HandleResult<BasicDo>> dbModelGetter;
    private Function<VirtualDbLockInfoModel, VirtualDbLockResultModel> lockAllFunction;
    private Consumer<VirtualDbLockInfoModel> unLockAllFunction;
    //
    private OperateModelToVirtualDbHelper<BasicDo> operateModelToVirtualDbHelper;
    //
    private boolean isInit=false;

    public DefAddAttributeToVirtualDb(){

    }

    public void init(){
        if(isInit){
            return;
        }
        lockInfoGetter=new LockInfoGetter<>();
        unionTmpMappingWriter=new UnionTmpMappingWriter(insertUidxMappingFunction,null);
        dbModelGetter=new DbModelGetter<>(null,getByAttributeUidxFunction);
        lockAllFunction=new LockAllFunction(lockFunction);
        unLockAllFunction=new UnLockAllFunction(unLockFunction);
        //
        operateModelToVirtualDbHelper=new OperateModelToVirtualDbHelper();
        operateModelToVirtualDbHelper.setDbModelGetter(dbModelGetter);
        operateModelToVirtualDbHelper.setLockAllFunction(lockAllFunction);
        operateModelToVirtualDbHelper.setUnLockAllFunction(unLockAllFunction);
        isInit=true;
    }

    @Override
    public HandleResult<ModelAttributePkAndShadingInfoModel> insertModelAttribute(ModelBasicAttributeSvModel modelAttribute,
                                                      Long tenantId, String tenantExtCode,
                                                      VirtualDbAttributeIdxConfigModel attributeIdxConfig) {
        init();
        ParametersWrappedModel<BasicDo> parametersWrappedModel=new ParametersWrappedModel<>();
        parametersWrappedModel.setTenantId(tenantId);
        parametersWrappedModel.setTenantExtCode(tenantExtCode);
        parametersWrappedModel.setAttributeIdxConfig(attributeIdxConfig);
        Map<String,ModelBasicAttributeSvModel> codeToAttributeMap=new HashMap<>();
        codeToAttributeMap.put(modelAttribute.getAttributeCode(),modelAttribute);
        parametersWrappedModel.setCodeToAttributeMap(codeToAttributeMap);
        VirtualDbLockInfoModel virtualDbLockInfoModel = lockInfoGetter.apply(parametersWrappedModel);
        if(!virtualDbLockInfoModel.isNeedLock()){
            return doInserModelAttribute(modelAttribute);
        }
        return operateModelToVirtualDbHelper.lockAddMappingAndExecuteOperation(
                parametersWrappedModel,virtualDbLockInfoModel,
                (parametersWrapped,virtualDbLockInfo)
                        ->handleUnionTmpMapping(parametersWrapped,virtualDbLockInfoModel),
                (parametersWrapped)
                        ->doInserModelAttribute(modelAttribute));
    }

    private HandleResult<String> handleUnionTmpMapping(ParametersWrappedModel<BasicDo> parametersWrappedModel,
                                          VirtualDbLockInfoModel virtualDbLockInfoModel){
        //5.写唯一性索引到反查表中--事务性写入
        HandleResult<String> mappingWriteResult=unionTmpMappingWriter.apply(virtualDbLockInfoModel);
        return mappingWriteResult;
    }

    private HandleResult<ModelAttributePkAndShadingInfoModel> doInserModelAttribute(ModelBasicAttributeSvModel modelAttribute){
        return attributeInsertFunction.apply(modelAttribute);
    }

    //////////////////////////////////////////
    public void setAttributeInsertFunction(Function<ModelBasicAttributeSvModel,
            HandleResult<ModelAttributePkAndShadingInfoModel>> attributeInsertFunction) {
        this.attributeInsertFunction = attributeInsertFunction;
    }

    public void setInsertUidxMappingFunction(Function<UnionIdxMappingSvModel, Integer> insertUidxMappingFunction) {
        this.insertUidxMappingFunction = insertUidxMappingFunction;
    }

    public void setGetByAttributeUidxFunction(Function<GetByUnionIdxParameterModel, BasicDo> getByAttributeUidxFunction) {
        this.getByAttributeUidxFunction = getByAttributeUidxFunction;
    }

    public void setLockFunction(Function<String, Boolean> lockFunction) {
        this.lockFunction = lockFunction;
    }

    public void setUnLockFunction(Consumer<String> unLockFunction) {
        this.unLockFunction = unLockFunction;
    }
}
